
object Hanoi
{
    def main() : Unit = 
    {{
        println(new HAN().start(25));
    }}
}

class HAN
{
	var towerA : Int[];
	var towerB : Int[];
	var towerC : Int[];
	
	def start(n: Int) : Int =
	{
		var unused : Int;
		
		towerA = new Int[n];
		towerB = new Int[n];
		towerC = new Int[n];
		
		unused = this.constructHanoi(n);
		
		unused = this.printTowers();
		unused = this.move(n, towerA, towerC, towerB);
		unused = this.printTowers();
			
		return 0;
	}
		
	def constructHanoi(n : Int) : Int =
	{
		//Fill up tower A with corresponding Cakes
		var i : Int;
		var j : Int;
		
		i = 0;
		j = n+1;
		
		while(i<n)
		{
			towerA[i] = j;
			towerB[i] = 0;
			towerC[i] = 0;
			
			j = j-1;
			i = i+1;
		}
		return 0;
	}

	def move(n: Int, towerS: Int[], towerD: Int[], towerA: Int[]) : Int =
	{
		var unused : Int;
		
		if(1<n)
		{
			unused = this.move(n-1, towerS, towerA, towerD);
			unused = this.moveCake(towerS, towerD);
			unused = this.move(n-1, towerA, towerD, towerS);
		} else
		{
			unused = this.moveCake(towerS, towerD);
		}
		
		return 0;
	}
	
	def moveCake(towerS : Int[], towerD : Int[]) : Int = 
	{
		var i : Int;
		var j : Int;
		var cake : Int;
		
		//Find Upper Cake of Source Tower
		i = this.upperCake(towerS);
			
		//Pick the cake			
		cake = towerS[i];
		towerS[i] = 0;
		
		//Find Upper Cake of Destination Tower
		j = this.upperCake(towerD);
		//Most upper Cake is at j so put at j+1
		towerD[j+1] = cake;		
		
		return 0;
	}
	
	def upperCake(tower : Int[]) : Int =
	{
		var i : Int;
		i = tower.length-1;
		
		while((0<i || i==0) && tower[i]==0)
		{
			i = i-1;
		}
		//Most upper Cake is at i
		return i;
	}
	
	def printTowers() : Int =
	{
		println("TowerA:"+this.printTower(towerA)); //[this.upperCake(towerA)]+" | TowerB:"+towerB[this.upperCake(towerB)]+" | TowerC:"+towerC[this.upperCake(towerC)]);
		println("TowerB:"+this.printTower(towerB));
		println("TowerC:"+this.printTower(towerC));
		println("----------------");
		return 0;
	}
	
	def printTower(tower : Int[]) : Int = 
	{
		//This might be improved...
		return tower[0];
	}
}